﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Complaint.Models.Dtos;

namespace Complaint.Repositories.Helpers
{
    public static class LINQHelper
    {
        public static Expression<Func<T, bool>> GetWhereInExpression<T, TValue>(
            Expression<Func<T, TValue>> valueSelector, IEnumerable<TValue> values
        )
        {

            if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); }

            if (null == values) { throw new ArgumentNullException("values"); }

            ParameterExpression p = valueSelector.Parameters.Single();

            if (!values.Any())
            {
                return e => false;
            }

            var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));

            var body = equals.Aggregate(Expression.Or);

            return Expression.Lambda<Func<T, bool>>(body, p);

        }

        public static IQueryable<Models.Dtos.Complaint> ApplyCategoryFilter(this IQueryable<Models.Dtos.Complaint> source, int[] categoryId)
        {
            source = source.Include("Organisation.Category");
            IQueryable<Models.Dtos.Complaint> result = new List<Models.Dtos.Complaint>().AsQueryable();
            IQueryable<Models.Dtos.Complaint> temp;
            if (categoryId.Length == 0) return source;

            foreach (var id in categoryId)
            {
                var repo = new CategoryRepository();
                var category = repo.FindById(id);
                temp = source.ToList().
                                Where(c => c.Organisation.Category.Any(
                                            cc => SearchChildren(category, cc.CategoryID)
                                            )
                                    )
                                .AsQueryable();
                if (result.Count() == 0)
                {
                    if (temp.Count() > 0)
                        result = temp;
                }
                else
                {
                    result = result.Union(temp.AsEnumerable());
                }
            }
            return result;
        }

        private static bool SearchChildren(Category category, int id)
        {
            if (category.CategoryID.Equals(id))
            {
                return true;
            }
            category.Children.Load();
            return category.Children.Select(c => SearchChildren(c, id)).FirstOrDefault();
        }
    }
}
